#include "StdAfx.h"
#include "Object.h"

Object::Object(void)
{
	worldMatrix.SetIdentity();
	scale = Vector3(1, 1, 1);
	strcpy(fs_path, "../Resources/Shaders/TriangleShaderFS.fs");
	strcpy(vs_path, "../Resources/Shaders/TriangleShaderVS.vs");
	lightColor = Vector3(1, 1, 1);
}

Object::~Object(void)
{
}


void Object::Scale(float Sx, float Sy, float Sz)
{
	scale = Vector3(Sx, Sy, Sz);
	calculateWorldMatrix();
}
void Object::Rotate(float Rx, float Ry, float Rz)
{
	rotate = Vector3(Rx, Ry, Rz);
	calculateWorldMatrix();
}
void Object::Place(float Px, float Py, float Pz)
{
	displace = Vector3(Px, Py, Pz);
	calculateWorldMatrix();
}


Matrix Object::getWorldMatrix()
{
	return worldMatrix;
}


void Object::moveLeft()
{
	displace.x+=TRANSLATE_STEP;
	calculateWorldMatrix();
}
void Object::moveRight()
{
	displace.x-=TRANSLATE_STEP;
	calculateWorldMatrix();
}
void Object::moveForward()
{
	displace.z+=TRANSLATE_STEP;
	calculateWorldMatrix();
}
void Object::moveBackward()
{
	displace.z-=TRANSLATE_STEP;
	calculateWorldMatrix();
}

void Object::RotateLeft()
{
	rotate.y += ROTATE_STEP;
	calculateWorldMatrix();
}
void Object::RotateRight()
{
	rotate.y += -ROTATE_STEP;
	calculateWorldMatrix();
}
void Object::RotateUp()
{ 
	rotate.x += -ROTATE_STEP;
	calculateWorldMatrix();
}
void Object::RotateDown()
{
	rotate.x += ROTATE_STEP;
	calculateWorldMatrix();
}

void Object::calculateWorldMatrix()
{
	Matrix translation, rx, ry, rz, rotation, scaling;
	translation.SetTranslation(displace);
	scaling.SetScale(scale);
	rx.SetRotationX(rotate.x);
	ry.SetRotationY(rotate.y);
	rz.SetRotationZ(rotate.z);
	rotation = rz * rx * ry;

	worldMatrix = scaling * rotation * translation;
}

void Object::setNormalMap(char* tga)
{
	glGenTextures(1, &normal_map_id);
	
	glBindTexture(GL_TEXTURE_2D, normal_map_id);
	int width, height, bpp;
	char* imgData = LoadTGA(tga, &width, &height, &bpp);
	//
	if (bpp == 24)
		//RGB
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, imgData);
	else
		//RGBA
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imgData);

	delete[] imgData;


	//
	////filter for minification
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	////filter for magnification
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	//// gen mipmap
	glGenerateMipmap(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, 0);
}

int Object::Load(char* file_nfg, char* file_tga)
{
	//==================Load model
	if (model.Load(file_nfg) == LOAD_FAILED)
		return LOAD_FAILED;

	//==================Load texture
	glGenTextures(1, &texture_id);
	glBindTexture(GL_TEXTURE_2D, texture_id);
	int width, height, bpp;
	char* imgData = LoadTGA(file_tga, &width, &height, &bpp);
	//
	if (bpp == 24)
		//RGB
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, imgData);
	else
		//RGBA
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imgData);

	delete[] imgData;


	//
	////filter for minification
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	////filter for magnification
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	//// gen mipmap
	glGenerateMipmap(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, 0);

	glGenBuffers(1, &vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferData(GL_ARRAY_BUFFER, model.num_vertices * sizeof(Vertex), model.vertices, GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	glGenBuffers(1, &ibo);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, model.num_indices * sizeof(GLushort), model.indices, GL_STATIC_DRAW);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	myShaders.Init(vs_path, fs_path);

	return LOAD_SUCCEEDED;

}


void Object::Draw( ESContext *esContext, Camera* camera)
{
	glUseProgram(myShaders.program);
	// Open buffer
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);

	// Bind Vertex to Shaders
	glEnableVertexAttribArray(myShaders.positionAttribute);
	glVertexAttribPointer(myShaders.positionAttribute, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
	glEnableVertexAttribArray(myShaders.uvAttribute);
	glVertexAttribPointer(myShaders.uvAttribute, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (char*)0 + sizeof(Vector3) + sizeof(Vector4));

	// Bind Texture

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, texture_id);
	glUniform1i(myShaders.textureUniform, 0);

	// Bind MVP Matrix
	Matrix mvp =  getWorldMatrix() * camera->getViewMatrix() * camera->getProjectionMatrix();
	glUniformMatrix4fv(myShaders.matMVPUniform, 1, GL_FALSE, &(mvp.m[0][0]));

	// Bind Index
	int size;
	glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size);


	// Draw
	glDrawElements(GL_TRIANGLES, size / sizeof(GLushort), GL_UNSIGNED_SHORT, 0);

	// Release buffer
	glBindTexture(GL_TEXTURE_2D, 0);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}


void Object::Update ( ESContext *esContext, float deltaTime)
{

}
